import Axios, {AxiosInstance, AxiosRequestConfig} from "axios";
import {OkHttpRequestConfig, RequestMethods} from "./types";
import {UserPreferenceStore} from "@/utils/UserPreferenceStore.ts";
import {showDialog, showToast} from "vant";

const {VITE_APP_BASE_API} = import.meta.env;

const defaultConfig: AxiosRequestConfig = {
    // 请求超时时间
    timeout: 10000,
    // 后端请求地址
    baseURL: VITE_APP_BASE_API,
    // 请求头
    headers: {
        Accept: "application/json, text/plain, */*",
        "Content-Type": "application/json",
        "X-Requested-With": "XMLHttpRequest"
    }
};

class Okhttp {

    /** 构造函数 */
    constructor() {
        // 请求拦截器
        this.requestInterceptors();
        // 响应拦截器
        this.responseInterceptors();
    }


    /** 保存当前Axios实例对象 */
    private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

    /**
     * 请求拦截器
     * @private 私有方法
     */
    private requestInterceptors() {

        Okhttp.axiosInstance.interceptors.request.use(async (config: OkHttpRequestConfig): Promise<any> => {

                /** 请求白名单，放置一些不需要token的接口（通过设置请求白名单，防止token过期后再请求造成的死循环问题） */
                const whiteList = [
                    "/refreshToken",
                    "/login",
                    "/loan",
                    "/sms"
                ];
                return whiteList.some(v => config.url?.endsWith(v))
                    ? config
                    : new Promise(resolve => {
                        const data = UserPreferenceStore.getInstance().getToken();
                        config.headers!["Authorization"] = "Bearer " + data;
                        resolve(config);
                    });
            },
            error => {
                console.log(error);
                return Promise.reject(error);
            }
        )
    }


    /** 通用请求工具函数 */
    public request<T>(
        method: RequestMethods,
        url: string,
        param?: AxiosRequestConfig,
        axiosConfig?: OkHttpRequestConfig
    ): Promise<T> {
        const config = {
            method,
            url,
            ...param,
            ...axiosConfig
        } as OkHttpRequestConfig;

        // 单独处理自定义请求/响应回调
        return new Promise((resolve, reject) => {
            Okhttp.axiosInstance
                .request(config)
                .then((response: any) => {
                    resolve(response);
                })
                .catch(error => {
                    // 某些情况网络失效，此时直接进入error流程，所以在这边也进行拦截
                    if (error.response && error.response.status >= 500) {
                        console.log("message(\"网络异常\", { type: \"error\" });")
                    }

                    if (
                        error.response &&
                        error.response.status >= 400 &&
                        error.response.status < 500
                    ) {
                        console.log("message(\"请求接口不存在\", { type: \"error\" });")
                    }

                    reject(error);
                });
        });
    }

    public post<T, P>(
        url: string,
        params?: AxiosRequestConfig<T>,
        config?: OkHttpRequestConfig
    ): Promise<P> {
        return this.request<P>("post", url, params, config);
    }

    /**
     *  响应拦截器
     * @private 私有方法
     */
    private responseInterceptors() {
        // 响应拦截器
        Okhttp.axiosInstance.interceptors.response.use(
            response => {

                const msg = response.data?.msg;

                if (response.data.code !== 0) {

                    // 判定token失效时弹出过期提示
                    if (response.data.code === 106 || response.data.code === 107) {
                        // http://192.168.21.25:5173/loan/#/main/index
                        showDialog({message: '登录失效,请重新登录'}).then(() => {
                            // 清理登录信息
                            UserPreferenceStore.getInstance().clearUserInfo();
                            // 跳转到登录页
                            window.location.href = "/";
                        });

                        return Promise.reject(msg);
                    } else {
                        // 不等于0 、并且不等于106、107时，弹出提示
                        showToast(msg)
                        // 触发错误回调
                        return Promise.reject(msg);
                    }
                }



                return response.data;
            },
            error => {
                Axios.isCancel(error)
                console.log("response error", error);
                return Promise.reject(error);
            }
        )
    }
}

export const http = new Okhttp();
